package com.home.config;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.home.properties.RedisConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.util.StringUtils;
import redis.clients.jedis.JedisPoolConfig;

import javax.annotation.Resource;

/**
 * @ClassName: RedisConfiguration
 * @Description:
 * @Author: VT
 * @Date: 2020-09-14 22:39
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(RedisConfig.class)
public class RedisConfiguration implements DisposableBean {
    @Resource
    RedisConfig redisConfig;

    /**
     * @return
     */
    @Bean(name = "redisTemplate")
    public StringRedisTemplate redisTemplate() {
        log.info("this is redisTemplate. config={}", JSONObject.toJSONString(redisConfig));
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(
                connectionFactory(redisConfig.getHost(), redisConfig.getPort(), redisConfig.getPassword(),
                        redisConfig.getMaxIdle(), redisConfig.getMinIdle(),
                        redisConfig.getMaxTotal(), redisConfig.getMaxWaitMillis(), redisConfig.getTimeout()));

        redisTemplateConfig(template);
        return template;
    }

    /**
     * @param template
     */
    private void redisTemplateConfig(StringRedisTemplate template) {
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
    }


    /**
     * @param hostName
     * @param port
     * @param password
     * @param maxIdle
     * @param minIdle
     * @param maxTotal
     * @param maxWaitMillis
     * @param timeout
     * @return
     */
    public RedisConnectionFactory connectionFactory(String hostName, int port, String password, int maxIdle, int minIdle,
                                                    int maxTotal, long maxWaitMillis, int timeout) {
        JedisConnectionFactory jedis = new JedisConnectionFactory();
        jedis.setHostName(hostName);
        jedis.setPort(port);
        if (!StringUtils.isEmpty(password)) {
            jedis.setPassword(password);
        }
        jedis.setPoolConfig(poolCofig(maxIdle, minIdle, maxTotal, maxWaitMillis));
        // 初始化连接pool
        jedis.afterPropertiesSet();
        jedis.setTimeout(timeout);
        RedisConnectionFactory factory = jedis;

        return factory;
    }

    /**
     * @param maxIdle
     * @param minIdle
     * @param maxTotal
     * @param maxWaitMillis
     * @return
     */
    public JedisPoolConfig poolCofig(int maxIdle, int minIdle, int maxTotal, long maxWaitMillis) {
        JedisPoolConfig poolCofig = new JedisPoolConfig();
        poolCofig.setMaxIdle(maxIdle);
        poolCofig.setMinIdle(minIdle);
        poolCofig.setMaxTotal(maxTotal);
        poolCofig.setMaxWaitMillis(maxWaitMillis);
        poolCofig.setTestOnBorrow(true);
        poolCofig.setTestOnReturn(true);
        return poolCofig;
    }

    @Override
    public void destroy() throws Exception {
        log.info("RedisConfiguration destroy...");
    }
}
